晓晓的个人博客Logo
晓晓的个人博客
Defer 脚本会延迟 DOMContentLoaded 的触发时机吗?
AI提炼icon
提炼
本文围绕多个 defer 脚本对 DOMContentLoaded 事件触发的影响展开。当多个 defer 脚本下载与执行时,若有脚本下载缓慢或执行耗时,会阻塞延迟该事件触发,因浏览器遵循所有 defer 脚本执行完才触发此事件的规则。defer 脚本下载异步但执行同步,按顺序依次执行,任一脚本慢都会影响后续。DOMContentLoaded 事件延迟触发,会导致用户体验变差,页面交互功能无法工作,同时使 DOMContentLoaded 时间这一性能指标变差,影响性能测评分数。解决方案包括保持 defer 脚本轻量,避免重量级操作;进行代码拆分与合并,减少请求数与调度,拆分大脚本非关键逻辑到事件后执行。最后强调前端工程师应保证 defer 脚本轻量,且 defer 对页面内联 script 标签无效。
本文于 2025-09-02 21:13 首次发布,最后修改于 2025-09-03 07:30

直击答案

答案:会。

这是因为浏览器需要严格遵循“只有在 defer 文件都下载、执行完毕之后才能触发 DOMContentLoaded 事件”这一明确的执行顺序,所以当有多个 defer 脚本需要下载与执行时,如果其中一个或多个脚本下载缓慢或执行耗时的话,那就会直接阻塞和延迟 DOMContentLoaded 事件的触发(下图清晰的展示了其中的依赖关系)。

答疑解惑

defer 脚本与 DOMContentLoaded

1.defer 脚本的执行是同步的

虽然 defer 脚本的下载是异步的(不阻塞 HTML 解析),但它们的执行是严格按照顺序、同步进行的。浏览器会等待第一个 defer 脚本下载并执行完毕,再开始执行下一个,以此类推。任何一个脚本执行过慢,都会阻塞后续脚本的执行。

2.DOMContentLoaded 必须等待

DOMContentLoaded 事件的设计本意就是:“当初始 HTML 文档被完全加载和解析,并且所有延迟脚本(defer)都执行完毕时”才触发。因此,事件触发前的那一刻,浏览器必须确保所有 defer 脚本都已完成执行。这是 Web 标准规定的行为。

当 DOMContentLoaded 事件被延迟触发,会带来什么影响?

当 DOMContentLoaded 事件被延迟触发,首当其冲的影响就是用户体验问题:用户会感觉页面“卡住了”。虽然此时页面已经可以被看到,但是任何依赖于 DOMContentLoaded 事件来初始化的交互功能都无法工作,因为交互功能的初始化脚本还在排队等待执行。

其次受到影响的就是让程序员头秃的性能指标:Web 性能关键指标 DOMContentLoaded 时间 (DCL) 会变得非常差,这会直接影响 Lighthouse 等性能测评工具的分数。

解决方案(既然影响这么大,就让程序员加班解决吧)

1.保持 defer 脚本轻量

完美的 defer 脚本应该只包含组件定义、注册和关键的初始化前置逻辑,应避免执行重量级的同步计算、同步网络请求等操作;

2.代码拆分与合并

可以将多个小文件合并成一个,以减少 HTTP 请求数量和脚本执行调度;

但如果有一个非常大的、非关键的脚本,可以在分析后将重要逻辑拆解出来独立成一个文件,另将不紧急或耗时的逻辑放到 DOMContentLoaded 事件之后执行;

写在最后

综上,defer 脚本在下载阶段是性能助手,但在执行阶段却可能成为瓶颈。所以作为前端工程师的我们必须履行“契约”:保证它轻装上阵,这样才不辜负它为我们提供了一个可靠的、可预测的执行顺序(在 DOM 构建后,在 DCL 前)。

P.S. defer 是一个为外部脚本设计的性能优化属性,所以当在页面內联的 script 标签中设置 defer 时是没有效果的。

0个赞
喜欢就点个赞吧